#include "RenderItemManager.h"
#include "RenderItem.h"
#include "Game.h"
#include "Mesh.h"
#include "BasicEffect.h"
#include "DepthEffect.h"
#include "ShadowEffect.h"
#include "ShadowRender.h"

RenderItemManager::RenderItemManager()
{
	mStartItem = 0;
}

RenderItemManager::RenderItemManager(const RenderItemManager&)
{

}

RenderItemManager::~RenderItemManager()
{

}

void RenderItemManager::Update()
{
	for(RenderItem* item = mStartItem;item != NULL;item = item->GetNext())
	{
		item->CalculDistance(Game::Instance()->GetCamera()->GetPosition());
	}
}

void RenderItemManager::SortIteration(int pIterationsCount)
{
	RenderItem* item = mStartItem;
	if(item == NULL) return;

	for(int i = 0;i < pIterationsCount;i++)
	{
		bool noMove = true;
		RenderItem* nextItem = mStartItem->GetNext();
		while(nextItem != NULL)
		{
			if(item->GetDistance() > nextItem->GetDistance())
			{
				MoveForward(item);
				noMove = false;
			}
			else
			{
				item = nextItem;
			}
			nextItem = item->GetNext();
		}
		if(noMove) break;
		item = mStartItem;
	}
}

void RenderItemManager::SortIterationDesc(int pIterationsCount)
{
	RenderItem* item = mStartItem;
	if(item == NULL) return;

	for(int i = 0;i < pIterationsCount;i++)
	{
		bool noMove = true;
		RenderItem* nextItem = mStartItem;
		while(nextItem != NULL)
		{
			if(item->GetDistance() < nextItem->GetDistance())
			{
				MoveForward(item);
				noMove = false;
			}
			else
			{
				item = nextItem;
			}
			nextItem = item->GetNext();
		}
		if(noMove) break;
		item = mStartItem;
	}
}

void RenderItemManager::MoveForward(RenderItem* item)
{
	RenderItem* itemToFlip = item->GetNext();
	if(itemToFlip == NULL)	return;

	RenderItem* backItem = item->GetPrevious();
	RenderItem* forwardItem = itemToFlip->GetNext();

	if(backItem != NULL)
		backItem->SetNext(itemToFlip);
	else
		mStartItem = itemToFlip;

	itemToFlip->SetPrevious(backItem);
	itemToFlip->SetNext(item);
	
	item->SetPrevious(itemToFlip);
	item->SetNext(forwardItem);

	if(forwardItem != NULL) 
		forwardItem->SetPrevious(item);
}

void RenderItemManager::MoveBack(RenderItem* item)
{
	RenderItem* itemToFlip = item->GetPrevious();
	if(itemToFlip == NULL)	return;

	RenderItem* backItem = itemToFlip->GetPrevious();
	RenderItem* forwardItem = item->GetNext();

	if(backItem != NULL)
		item->SetNext(itemToFlip);
	else
		mStartItem = item;

	item->SetPrevious(backItem);
	item->SetNext(itemToFlip);

	itemToFlip->SetPrevious(item);
	itemToFlip->SetNext(forwardItem);
	

	if(forwardItem != NULL) 
		forwardItem->SetPrevious(itemToFlip);
}

void RenderItemManager::AddItem(RenderItem* item)
{
	if(mStartItem == NULL)
	{
		mStartItem = item;
		return;
	}
	else
	{
		mStartItem->SetPrevious(item);
		item->SetNext(mStartItem);
		mStartItem = item;
	}
}

void RenderItemManager::Render()
{
	XMFLOAT4X4* viewMatrix;
	XMFLOAT4X4* projectionMatrix;
	XMFLOAT4X4 worldMatrix;

	viewMatrix = Game::Instance()->GetCamera()->GetViewMatrix();
	projectionMatrix = CDirect3D::Instance()->GetProjectionMatrix();
	BasicEffect* shader = Game::Instance()->GetShader();

	for(RenderItem* item = mStartItem;item != NULL;item = item->GetNext())
	{
		Mesh* mesh = item->GetMesh();
		mesh->IASetVertices();
		mesh->IASetIndices();
		mesh->IASetTexture();

		worldMatrix = item->GetModel3DInstance()->GetTransform();

		shader->SetTransformsMatrices(worldMatrix, *viewMatrix, *projectionMatrix);
		shader->Render(mesh->GetIndicesCount());
	}
}

void RenderItemManager::RenderShadow(XMFLOAT4X4* pLightViewMatrix, XMFLOAT4X4* pLightProjectionMatrix, XMFLOAT4X4* pLightLargeViewMatrix, XMFLOAT4X4* pLightLargeProjectionMatrix)
{
	XMFLOAT4X4* viewMatrix;
	XMFLOAT4X4* projectionMatrix;
	XMFLOAT4X4 worldMatrix;

	viewMatrix = Game::Instance()->GetCamera()->GetViewMatrix();
	projectionMatrix = CDirect3D::Instance()->GetProjectionMatrix();
	ShadowEffect* shader = Game::Instance()->GetShadowRender()->GetShadowEffect();

	for(RenderItem* item = mStartItem;item != NULL;item = item->GetNext())
	{
		Mesh* mesh = item->GetMesh();
		mesh->IASetVertices();
		mesh->IASetIndices();

		worldMatrix = item->GetModel3DInstance()->GetTransform();

		shader->SetTransformsMatrices(worldMatrix, *viewMatrix, *projectionMatrix, *pLightViewMatrix, *pLightProjectionMatrix, *pLightLargeViewMatrix, *pLightLargeProjectionMatrix);
		shader->Render(mesh->GetIndicesCount());
	}
}

void RenderItemManager::DepthRender(XMFLOAT4X4* pLightViewMatrix, XMFLOAT4X4* pLightProjectionMatrix)
{
	XMFLOAT4X4 worldMatrix;

	DepthEffect* shader = Game::Instance()->GetShadowRender()->GetDepthEffect();

	for(RenderItem* item = mStartItem;item != NULL;item = item->GetNext())
	{
		Mesh* mesh = item->GetMesh();
		mesh->IASetVertices();
		mesh->IASetIndices();
		mesh->IASetTexture();

		worldMatrix = item->GetModel3DInstance()->GetTransform();

		shader->SetTransformsMatrices(worldMatrix, *pLightViewMatrix, *pLightProjectionMatrix);
		shader->Render(mesh->GetIndicesCount());
	}
}

void RenderItemManager::RaiseAllRemoveFlags()
{
	for(RenderItem* item = mStartItem;item != NULL;item = item->GetNext())
	{
		item->RaiseRemoveFlags();
	}
}

void RenderItemManager::RemoveItemsByFlag()
{
	RenderItem* item = mStartItem;
	while(item != NULL)
	{
		RenderItem* nextItem = item->GetNext();
		if(item->GetRemoveFlag())
		{
			item->StopRendering();
			if(item == mStartItem)
			{
				mStartItem = nextItem;
			}
		}
		item = nextItem;
	}
}